home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / xvisrc.zip / FIND.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  12KB  |  594 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)find.c    2.2 (Chris & John Downey) 7/29/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     find.c
  14. * module function:
  15.     Character and function searching.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21.  
  22. ***/
  23.  
  24. #include "xvi.h"
  25. #include "regexp.h"    /* Henry Spencer's regular expression routines */
  26.  
  27. #ifdef    MEGAMAX
  28. overlay "find"
  29. #endif
  30.  
  31. /*
  32.  * Character Searches
  33.  */
  34.  
  35. static char lastc;        /* last character searched for */
  36. static int  lastcdir;        /* last direction of character search */
  37. static int  lastctype;        /* last type of search ("find" or "to") */
  38.  
  39. /*
  40.  * searchc(c, dir, type, num)
  41.  *
  42.  * Search for character 'c', in direction 'dir'. If type is 0, move to
  43.  * the position of the character, otherwise move to just before the char.
  44.  * 'num' is the number of times to do it (the prefix number).
  45.  */
  46. Posn *
  47. searchc(ch, dir, type, num)
  48. int    ch;
  49. int    dir;
  50. int    type;
  51. int    num;
  52. {
  53.     static Posn        pos;            /* saved cursor posn */
  54.     enum mvtype        (*mvfunc) P((Posn *));
  55.     enum mvtype        (*backfunc) P((Posn *));
  56.     unsigned char    c;            /* as ch but uchar */
  57.     register int    i;            /* loop counter */
  58.  
  59.     /*
  60.      * Remember details in case we want to repeat the search.
  61.      */
  62.     lastc = ch;
  63.     lastcdir = dir;
  64.     lastctype = type;
  65.  
  66.     pos = *(curwin->w_cursor);    /* save position in case we fail */
  67.     c = ch;
  68.     if (dir == FORWARD) {
  69.     mvfunc = inc;
  70.     backfunc = dec;
  71.     } else {
  72.     mvfunc = dec;
  73.     backfunc = inc;
  74.     }
  75.  
  76.     /*
  77.      * On 'to' searches, skip one to start with so we can repeat
  78.      * searches in the same direction and have it work right.
  79.      */
  80.     if (type) {
  81.     if ((*mvfunc)(&pos) != mv_SAMELINE) {
  82.         return(NULL);
  83.     }
  84.     }
  85.  
  86.     for (i = 0; i < num; i++) {
  87.     bool_t    found;
  88.  
  89.     found = FALSE;
  90.     while ((*mvfunc)(&pos) == mv_SAMELINE) {
  91.         if ((unsigned char) gchar(&pos) == c) {
  92.         found = TRUE;
  93.         break;
  94.         }
  95.     }
  96.     if (!found) {
  97.         return(NULL);
  98.     }
  99.     }
  100.     if (type) {
  101.     (void) (*backfunc)(&pos);
  102.     }
  103.     return(&pos);
  104. }
  105.  
  106. /*ARGSUSED*/
  107. Posn *
  108. crepsearch(buffer, flag, num)
  109. Buffer    *buffer;
  110. int    flag;
  111. int    num;
  112. {
  113.     Posn    *newpos;
  114.     int    dir;
  115.     int    savedir;
  116.  
  117.     if (lastc == '\0') {
  118.     return(NULL);
  119.     }
  120.  
  121.     savedir = lastcdir;
  122.     if (flag) {
  123.     dir = (lastcdir == FORWARD) ? BACKWARD : FORWARD;
  124.     } else {
  125.     dir = lastcdir;
  126.     }
  127.  
  128.     newpos = searchc(lastc, dir, lastctype, num);
  129.  
  130.     lastcdir = savedir;        /* put direction of search back how it was */
  131.  
  132.     return(newpos);
  133. }
  134.  
  135. /*
  136.  * "Other" Searches
  137.  */
  138.  
  139. /*
  140.  * showmatch - move the cursor to the matching paren or brace
  141.  */
  142. Posn *
  143. showmatch()
  144. {
  145.     register char    initc;            /* initial char */
  146.     register enum mvtype
  147.                 (*move) P((Posn *));    /* function to move cursor */
  148.     register char    findc;            /* terminating char */
  149.     static Posn        pos;            /* current position */
  150.     char        c;
  151.     int            count = 0;
  152.     bool_t        found = FALSE;
  153.  
  154.     pos = *curwin->w_cursor;
  155.  
  156.     /*
  157.      * Move forward to the first bracket character after the cursor.
  158.      * If we get to EOF before a bracket, return NULL.
  159.      */
  160.     for (found = FALSE; !found; ) {
  161.     initc = gchar(&pos);
  162.     switch (initc) {
  163.     case '(':
  164.         findc = ')';
  165.         move = inc;
  166.         found = TRUE;
  167.         break;
  168.     case ')':
  169.         findc = '(';
  170.         move = dec;
  171.         found = TRUE;
  172.         break;
  173.     case '{':
  174.         findc = '}';
  175.         move = inc;
  176.         found = TRUE;
  177.         break;
  178.     case '}':
  179.         findc = '{';
  180.         move = dec;
  181.         found = TRUE;
  182.         break;
  183.     case '[':
  184.         findc = ']';
  185.         move = inc;
  186.         found = TRUE;
  187.         break;
  188.     case ']':
  189.         findc = '[';
  190.         move = dec;
  191.         found = TRUE;
  192.         break;
  193.     default:
  194.         if (inc(&pos) == mv_NOMOVE) {
  195.         return(NULL);
  196.         }
  197.     }
  198.     }
  199.  
  200.     /*
  201.      * Move in the appropriate direction until we find a matching
  202.      * bracket or reach end of file.
  203.      */
  204.     while ((*move)(&pos) != mv_NOMOVE) {
  205.     c = gchar(&pos);
  206.     if (c == initc) {
  207.         count++;
  208.     } else if (c == findc) {
  209.         if (count == 0)
  210.         return(&pos);
  211.         count--;
  212.     }
  213.     }
  214.     return(NULL);            /* never found it */
  215. }
  216.  
  217. /*
  218.  * Find the nth next occurrence of str in the specified direction.
  219.  */
  220. Posn *
  221. find_pattern(str, dir, num)
  222. char    *str;
  223. int    dir;
  224. int    num;
  225. {
  226.     Posn    *p;
  227.     Posn    *lastp;
  228.  
  229.     p = curwin->w_cursor;
  230.     lastp = NULL;
  231.     while (num-- > 0) {
  232.     p = nsearch(curwin, p->p_line, p->p_index, dir, str);
  233.     if (p != NULL) {
  234.         lastp = p;
  235.     } else {
  236.         break;
  237.     }
  238.     }
  239.  
  240.     return(lastp);
  241. }
  242.  
  243. /*
  244.  * The following routines do the word searches performed by the
  245.  * 'w', 'W', 'b', 'B', 'e', and 'E' commands.
  246.  */
  247.  
  248. /*
  249.  * To perform these searches, characters are placed into one of three
  250.  * classes, and transitions between classes determine word boundaries.
  251.  *
  252.  * The classes are:
  253.  *
  254.  * cl_white - white space
  255.  * cl_text  - letters, digits, and underscore
  256.  * cl_punc  - everything else
  257.  */
  258.  
  259. typedef enum {
  260.     cl_white,
  261.     cl_text,
  262.     cl_punc
  263. } cclass;
  264.  
  265. static    int    stype;        /* type of the word motion being performed */
  266.  
  267. #define is_white(c)    (((c) == ' ') || ((c) == '\t') || ((c) == '\0'))
  268. #define is_text(c)    (is_alnum(c) || ((c) == '_'))
  269.  
  270. /*
  271.  * cls(c) - returns the class of character 'c'
  272.  *
  273.  * The 'type' of the current search modifies the classes of characters
  274.  * if a 'W', 'B', or 'E' motion is being done. In this case, chars. from
  275.  * class "cl_punc" are reported as class "cl_text" since only white space
  276.  * boundaries are of interest.
  277.  */
  278. static cclass
  279. cls(c)
  280. char    c;
  281. {
  282.     if (is_white(c))
  283.     return(cl_white);
  284.  
  285.     if (is_text(c))
  286.     return(cl_text);
  287.  
  288.     /*
  289.      * If stype is non-zero, report these as class 1.
  290.      */
  291.     return((stype == 0) ? cl_punc : cl_text);
  292. }
  293.  
  294.  
  295. /*
  296.  * fwd_word(pos, type, skip_white) - move forward one word
  297.  *
  298.  * Returns the resulting position, or NULL if EOF was reached.
  299.  *
  300.  * The extra argument "skip_white" (which is only used in fwd_word,
  301.  * but also included in bck_word and end_word for compatibility) is
  302.  * used to indicate whether to skip over white space to get to the
  303.  * start of the next word. If it is FALSE, the position returned will
  304.  * be the first white-space character (or punctuation) encountered.
  305.  * This is used by one command only: "cw".
  306.  */
  307. Posn *
  308. fwd_word(p, type, skip_white)
  309. Posn    *p;
  310. int    type;
  311. bool_t    skip_white;
  312. {
  313.     static    Posn    pos;
  314.     cclass        sclass;        /* starting class */
  315.  
  316.     stype = type;
  317.     sclass = cls(gchar(p));
  318.  
  319.     pos = *p;
  320.  
  321.     /*
  322.      * We always move at least one character.
  323.      */
  324.     if (inc(&pos) == mv_NOMOVE)
  325.     return(NULL);
  326.  
  327.     if (sclass != cl_white) {
  328.     /*
  329.      * We were in the middle of a word to start with.
  330.      * Move right until we change character class.
  331.      */
  332.     while (cls(gchar(&pos)) == sclass) {
  333.         if (inc(&pos) == mv_NOMOVE) {
  334.         /*
  335.          * Got to EOF. Return current position.
  336.          */
  337.         return(&pos);
  338.         }
  339.     }
  340.  
  341.     /*
  342.      * If we went from punctuation -> text
  343.      * or text -> punctuation, return here.
  344.      *
  345.      * If we went text/punctuation -> whitespace,
  346.      * we want to continue to the start of the
  347.      * next word, if there is one.
  348.      */
  349.     if (cls(gchar(&pos)) != cl_white)
  350.         return(&pos);
  351.     }
  352.  
  353.     /*
  354.      * We're in white space; go to next non-white.
  355.      */
  356.     if (skip_white) {
  357.     while (cls(gchar(&pos)) == cl_white) {
  358.         /*
  359.          * We'll stop if we land on a blank line
  360.          */
  361.         if (pos.p_index == 0 && pos.p_line->l_text[0] == '\0')
  362.         break;
  363.  
  364.         if (inc(&pos) == mv_NOMOVE) {
  365.         /*
  366.          * We have reached end of file; if we are at
  367.          * the beginning of a line, just return that
  368.          * position, otherwise try to back up so that
  369.          * we are still within the line.
  370.          */
  371.         if (pos.p_index != 0) {
  372.             (void) dec(&pos);
  373.         }
  374.         break;
  375.         }
  376.     }
  377.  
  378.     /*
  379.      * If we didn't move, return NULL.
  380.      */
  381.     if (pos.p_line == p->p_line && pos.p_index == p->p_index) {
  382.         return(NULL);
  383.     }
  384.     }
  385.  
  386.     return(&pos);
  387. }
  388.  
  389. /*
  390.  * bck_word(pos, type, skip_white) - move backward one word
  391.  *
  392.  * Returns the resulting position, or NULL if EOF was reached.
  393.  */
  394. /*ARGSUSED*/
  395. Posn *
  396. bck_word(p, type, skip_white)
  397. Posn    *p;
  398. int    type;
  399. bool_t    skip_white;
  400. {
  401.     static    Posn    pos;
  402.